#pragma once
#include <iostream>
#include <poll.h>
#include <sys/time.h>
#include <string>
#include <unistd.h>
#include "../selectServer/Log.hpp"
#include "../selectServer/Sock.hpp"

using std::cout;
using std::endl;

class PollServer
{
public:
    static const int FD_NONE = -1;
    static const int NFDS = 3;

public:
    PollServer(const uint16_t &port = 8080, const int &timeout = 1000) : _port(port), _timeout(timeout), _nfds(NFDS)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "create base socket success");

        _fds = new struct pollfd[_nfds];
        for (int i = 0; i < _nfds; i++)
        {
            _fds[i].fd = FD_NONE;
            _fds[i].events = _fds[i].revents = 0;
        }
        _fds[0].fd = _listensock;
        _fds[0].events = POLLIN;
    }
    void Start()
    {
        while (true)
        {
            DebugPrint();
            // 使用poll进行等待
            int n = poll(_fds, _nfds, _timeout); // 阻塞等待
            switch (n)
            {
            case 0:
                // 没有链接到来
                logMessage(DEBUG, "time out...");
                break;
            case -1:
                // 读取失败
                logMessage(WARNING, "select error:%f : %s", errno, strerror(errno));
                break;
            default:
                // success 链接
                // logMessage(DEBUG,"get a new link ...");
                HandlerEvent();
                break;
            }
        }
    }
    ~PollServer()
    {
        if (_listensock >= 0)
            close(_listensock);
        if (_fds)
            delete[] _fds;
    }

private:
    void HandlerEvent() //
    {
        // 先遍历fdarr找到合法的文件描述符
        for (int i = 0; i < _nfds; i++)
        {
            // cout<<i<<" ";
            if (_fds[i].fd == FD_NONE)
                continue;
            // 合法的不一定都是就绪的
            if (_fds[i].revents & POLLIN)
            {
                // 合法且就绪
                if (_fds[i].fd == _listensock)
                {
                    //cout << "goto Accept" << endl;
                    Accepter(); // listernsock就绪，获取新连接
                }
                else
                {
                    // 普通文件描述符，此时需要读取数据进行处理
                    Recv(i);
                }
            }
        }
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport = 0;

        // listernsock 上面的读取事件已经就绪
        int sock = Sock::Accept(_listensock, &clientip, &clientport); // accept不会阻塞
        if (sock < 0)
        {
            logMessage(WARNING, "Accept error");
            return;
        }
        logMessage(DEBUG, "get a new link success:[%s : %d]: %d", clientip.c_str(), clientport, sock);
        // 此时我们不能直接读取数据，因为我们只是获取了链接，并不清楚该链接的数据是否就绪，我们还需要将sock托管给poll
        // 让其帮我们去等待

        // 将提供服务的sock添加到文件描述符表中,让poll等待
        int pos = 1;
        for (; pos < _nfds; pos++)
        {
            if (_fds[pos].fd == FD_NONE)
                break;
        }
        if (pos == _nfds) // 链接满了--可以丢弃，也可以扩容
        {
            int newnfds = _nfds * 2;
            struct pollfd *tmp = (struct pollfd *)realloc(_fds, newnfds * sizeof(struct pollfd));
            if (tmp == nullptr)
            {
                logMessage(WARNING, "select server alredy full,close:%d", sock);
                close(sock);
            }
            else
            {
                for(int i=_nfds;i<newnfds;i++)
                {
                    tmp[i].fd = FD_NONE;
                    tmp[i].events=tmp[i].revents = 0;
                }
                _nfds = newnfds;
                _fds = tmp;
                logMessage(DEBUG, "realloc success");
                _fds[pos].fd = sock;
                _fds[pos].events = POLLIN;
            }
        }
        else
        {
            _fds[pos].fd = sock;
            _fds[pos].events = POLLIN;
        }
    }
    void Recv(int pos)
    {
        logMessage(DEBUG, "message in,get IO event:%d", _fds[pos].fd);
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer) - 1, 0); // 无法保证读取的是一整个报文
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "Client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if (n == 0)
        {
            // 客户端退出
            logMessage(DEBUG, "Client[%d] quite,mee too", _fds[pos].fd);
            // 关闭sock
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
        else
        {
            // 读取错误
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            close(_fds[pos].fd);
            _fds[pos].fd = FD_NONE;
            _fds[pos].events = 0;
        }
    }
    void DebugPrint()
    {
        cout << "_fd_array[]: ";
        for (int i = 0; i < _nfds; i++)
        {
            if (_fds[i].fd == FD_NONE)
                continue;
            cout << _fds[i].fd << " ";
        }
        cout << endl;
    }

private:
    uint16_t _port;
    int _listensock;
    struct pollfd *_fds;
    int _timeout;
    int _nfds;
};